package com.example.demo.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.BigExcelWriter;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.example.demo.entity.vo.PageVo;
import com.example.demo.enums.StatusCodeEnum;
import com.example.demo.exception.CustomException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @description：excel工具类.
 * @author：lw
 * @create_time：2024/1/12
 **/
public class MyExcelUtil{

    private static final String ext="xls";
//    private static final String ext="xlsx";

    public static<T> void export(HttpServletResponse response, PageVo<T> pageVo, Map<String,String> cols, String entityTitle){
        try (
                ExcelWriter writer = ExcelUtil.getWriter(ext.equals("xlsx"));   // 通过工具类创建writer，默认创建xls格式,传true创建xlsx。关闭writer，释放内存
                ServletOutputStream out=response.getOutputStream(); //关闭输出Servlet流
        ){
            cols.forEach(writer::addHeaderAlias);
            writer.setOnlyAlias(true);   // 只输出设置了别名的字段
            // 一次性写出内容，使用默认样式，强制输出标题
            writer.write(pageVo.getList(), true);
            //response为HttpServletResponse对象
            if(ext.equals("xls"))
            response.setContentType("application/vnd.ms-excel;charset=utf-8");   // xls
            else
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");  // xlsx
            String fileName="";
            if(pageVo.getCurrent()!=null && pageVo.getSize()!=null){
                String template = entityTitle+"表第{}页{}条_{}";
                fileName= StrUtil.format(template, pageVo.getCurrent(), pageVo.getSize(),System.currentTimeMillis());
            }else fileName=entityTitle;
            fileName= URLEncoder.encode(fileName, StandardCharsets.UTF_8);
            //文件名为中文的话请自行编码
            response.setHeader("Content-Disposition", "attachment;filename="+fileName);
            //out为OutputStream
            writer.flush(out, true);
        }catch (Throwable e){
            //response.setContentType("application/json");
            throw new RuntimeException("导出失败："+e.getMessage());
        }
    }

    public static<T> void exportBig(HttpServletResponse response, PageVo<T> pageVo, Map<String,String> cols, String entityTitle){
        try (
                BigExcelWriter writer= ExcelUtil.getBigWriter();   // 通过工具类创建writer，默认创建xls格式,传true创建xlsx。关闭writer，释放内存
                ServletOutputStream out=response.getOutputStream(); //关闭输出Servlet流
        ){
            cols.forEach((key, value) -> writer.addHeaderAlias(key, value));
            writer.setOnlyAlias(true);   // 只输出设置了别名的字段
            // 一次性写出内容，使用默认样式，强制输出标题
            writer.write(pageVo.getList(), true);
            //response为HttpServletResponse对象
            if(ext.equals("xls"))
            response.setContentType("application/vnd.ms-excel;charset=utf-8");   // xls
            else
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");  // xlsx
            String fileName="";
            if(pageVo.getCurrent()!=null && pageVo.getSize()!=null){
                String template = entityTitle+"表第{}页{}条_{}";
                fileName= StrUtil.format(template, pageVo.getCurrent(), pageVo.getSize(),System.currentTimeMillis());
            }else fileName=entityTitle;
            fileName= URLEncoder.encode(fileName, StandardCharsets.UTF_8);
            response.setHeader("Content-Disposition", "attachment;filename="+fileName);
            //out为OutputStream
            writer.flush(out, true);
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("导出失败："+e.getMessage());
        }
    }

    public static<T> List<T> read(MultipartFile file,Class<T> beanT){
        try(
                InputStream input=file.getInputStream();
                ExcelReader reader = ExcelUtil.getReader(input);
        ) {
            return  reader.readAll(beanT);
        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件读取失败："+e.getMessage());
        }
    }

    public static List<Map<String,Object>> read(MultipartFile file){
        try(
                InputStream input=file.getInputStream();
                ExcelReader reader = ExcelUtil.getReader(input);
        ) {
            return  reader.readAll();
        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("读取文件失败："+e.getMessage());
        }
    }

    public static<T> List<T> readBig(MultipartFile file,Class<T> beanT){
        List<List<Object>> list=new ArrayList<>();
        try(
                InputStream input=file.getInputStream();
        ) {
            ExcelUtil.readBySax(input, 0, (sheetIndex, rowIndex, rowData) -> {
                //二个参数是sheet的序号，-1表示读取所有sheet，0表示第一个sheet，依此类推。
                System.out.println(rowData);
                list.add(rowData);
            });
        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("导入失败："+e.getMessage());
        }
        List<Map<String,Object>> data=new ArrayList<>();
        List<Object> headerList=list.get(0);
        for (int i=1;i<list.size();i++){
            Map<String,Object> map=new LinkedHashMap<>();
            List<Object> values=list.get(i);
            for (int j=0;j<values.size();j++){
                map.put((String) headerList.get(j),values.get(j));
            }
            data.add(map);
        }
        List<T> res=new ArrayList<>();
        data.forEach(v->{
            try{
                res.add(BeanUtil.toBeanIgnoreCase(v,beanT,false));
            }
            catch (Exception e){
                throw new CustomException(StatusCodeEnum.import_error);
            }
        });

        return res;
    }

    public static List<Map<String,Object>> readBig(MultipartFile file){
        List<List<Object>> list=new ArrayList<>();
        try(
                InputStream input=file.getInputStream();
        ) {
            ExcelUtil.readBySax(input, 0, (sheetIndex, rowIndex, rowData) -> {
                //二个参数是sheet的序号，-1表示读取所有sheet，0表示第一个sheet，依此类推。
                System.out.println(rowData);
                list.add(rowData);
            });
        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("导入失败："+e.getMessage());
        }
        List<Map<String,Object>> data=new ArrayList<>();
        List<Object> headerList=list.get(0);
        for (int i=1;i<list.size();i++){
            Map<String,Object> map=new LinkedHashMap<>();
            List<Object> values=list.get(i);
            for (int j=0;j<values.size();j++){
                map.put((String) headerList.get(j),values.get(j));
            }
            data.add(map);
        }
        return  data;
    }

    /*
       关于导出样式的设置：
        分为4部分样式的设置
        1.头部样式 headCellStyle
        2.普通单元格样式 cellStyle
        3.数字单元格样式 cellStyleForNumber
        4.日期单元格样式 cellStyleForDate

        例子：
        // 获取普通单元格样式操作对象
        StyleSet style = writer.getStyleSet();
        CellStyle cellStyle = style.getHeadCellStyle();
        // 准备字体
        Font font = writer.createFont();
        font.setBold(true);
        font.setColor(Font.COLOR_RED);
        font.setItalic(true);
        //为普通单元格设置字体。第二个参数表示是否忽略头部样式
        cellStyle.setFont(font,true);
     */

}
